package cn.qyd.singlemodel;

import java.util.ArrayList;

/**
 * @author 邱运铎
 * @date 2024-03-14 21:17
 */
public class VolatileDoubleCheckDemo {
    // 这里volatile保证实例在new volatileDoubleCheckDemo的时候不会指令重排导致实例创建错误
    /**
     * a. memory = allocate() //分配内存
     * b. ctorInstanc(memory) //初始化对象
     * c. instance = memory   //设置instance指向刚分配的地址
     * 上面的代码在编译运行时，可能会出现重排序从 a-b-c 排序为 a-c-b。在多线程的情况下会出现以下问题。
     * 当线程 A 在执行第 5 行代码时，B 线程进来执行到第 2 行代码。假设此时 A 执行的过程中发生了指令重排序，
     * 即先执行了 a 和 c，没有执行 b。那么由于 A 线程执行了 c 导致 instance 指向了一段地址，
     * 所以 B 线程判断 instance 不为 null，会直接跳到第 6 行并返回一个未初始化的对象。
     */
    private static volatile VolatileDoubleCheckDemo instance;

    private VolatileDoubleCheckDemo() {};

    public static VolatileDoubleCheckDemo getInstance() {  //1
        if (instance == null) {                            //2
            synchronized (VolatileDoubleCheckDemo.class) { //3
                if (instance == null) { //4                //4
                    instance = new VolatileDoubleCheckDemo(); //5
                }
            }
        }

        return instance;                                //6
    }

    public static void main(String[] args) {
        ArrayList<VolatileDoubleCheckDemo> demos = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
               demos.add(VolatileDoubleCheckDemo.getInstance());
            }).start();
        }

        while (Thread.activeCount() > 2) {
            Thread.yield();
        }

        demos.forEach(System.out::println);


    }
}
